nestjs-commander, a nest command line tool
AI Response
If you want to integrate the 2dsphere
index creation into your NestJS CLI workflow, the best approach is to create a custom NestJS command that can be executed using nest
commands. This will follow the NestJS CLI style and allow better integration into your application lifecycle.
1. Create a Custom NestJS Command
NestJS allows creating command-line tools using nestjs-command
or nestjs-console
. We will use nestjs-command
for this.
Install Required Dependencies
필요한 패키지를 설치하세요:
bash
npm install nest-commander
그리고 package.json
에 스크립트를 추가하세요:
json
{
"scripts": {
"command": "nest start --entryFile=commands"
}
}
2. Implement the Command in src/commands/create-index.command.ts
Create a new directory src/commands/
and add a file create-index.command.ts
:
import { Injectable } from '@nestjs/common';
import { Command } from 'nestjs-command';
import { MongoClient } from 'mongodb';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class CreateIndexCommand {
constructor(private readonly configService: ConfigService) {}
@Command({
command: 'db:create-index',
describe: 'Create 2dsphere index on address.location.coordinates',
})
async createIndex() {
const uri = this.configService.get<string>('DATABASE_URL');
if (!uri) {
console.error('❌ DATABASE_URL is not set.');
return;
}
const client = new MongoClient(uri);
try {
await client.connect();
const db = client.db(); // Get the default database from the connection string
await db.collection('AcademyModel').createIndex({ 'address.location.coordinates': '2dsphere' });
console.log('✅ 2dsphere index created on address.location.coordinates');
} catch (error) {
console.error('❌ Error creating 2dsphere index:', error);
} finally {
await client.close();
}
}
}
3. Register the Command in app.module.ts
Modify app.module.ts
to include the command:
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommandModule } from 'nestjs-command';
import { CreateIndexCommand } from './commands/create-index.command';
@Module({
imports: [
ConfigModule.forRoot(), // Load environment variables
CommandModule,
],
providers: [CreateIndexCommand],
})
export class AppModule {}
4. Run the Command
Now you can run the custom command using the NestJS CLI:
pnpm run start db:create-index
# 아카데미 검색
npm run command search academy "XX아카데미"
# 코트 검색 (특정 아카데미 내에서)
npm run command search court "코트1" --academy "XX아카데미"
# 티켓플랜의 코트 업데이트 (추가)
npm run command update-ticket-plan-courts \
--academy "XX아카데미" \
--ticket-plan "프리미엄 플랜" \
--courts "코트1,코트2,코트3"
# 티켓플랜의 코트 교체
npm run command update-ticket-plan-courts \
--academy "XX아카데미" \
--ticket-plan "프리미엄 플랜" \
--courts "새코트1,새코트2" \
--replace
5. Automate It in package.json
Modify your package.json
script to run the Prisma migration and then create the index:
"scripts": {
"prisma:push": "npx prisma db push && pnpm run start db:create-index"
}
Now, whenever you run:
pnpm run prisma:push
It will:
- Push the Prisma schema to MongoDB.
- Automatically create the
2dsphere
index via the custom NestJS command.
Final Thoughts
✅ Follows NestJS CLI conventions
✅ Better error handling than raw shell scripts
✅ Uses NestJS dependency injection (ConfigService for env variables)
✅ Easier to extend for future commands
Would you like to add logging or extend this command further? 🚀
A. Chat GPT 4o
좋은 문제의식입니다. NestJS에서 개발자 편의 기능(DevOps/Debug API or CLI Tool) 을 제공하는 방식은 다음 두 가지 전략으로 나눌 수 있습니다:
✅ 선택지 요약
방법 | 장점 | 단점 | 추천 상황 |
---|---|---|---|
1. @Controller('dev')로 관리자 전용 API 구성 | Postman이나 Swagger로 바로 접근 가능 | 인증 없이 노출되면 위험 | 로컬/개발환경에서 빠른 조작 |
2. NestJS CLI Command (@Command()) 도입 | CI/CD나 SSH 환경에서 스크립트 실행 편리 | 실행결과를 API로 받을 수 없음 | 프로덕션에도 안전하게 사용 가능 |
3. 둘 다 지원 (API + CLI) | 유연성과 편의성 모두 확보 | 중복 코드 방지 필요 (Service 계층 분리 필수) | 개발과 운영 모두 고려할 때 |
🛠 추천 구현 구조
// TicketPlanService.ts
async updateTicketPlanCourts(academyName: string, ticketPlanName: string, newCourtIds: string[]) {
const academy = await this.academyRepo.findByName(academyName);
const ticketPlan = await this.ticketPlanRepo.findByNameAndAcademy(ticketPlanName, academy._id);
ticketPlan.courts = newCourtIds.map(id => new ObjectId(id));
await this.ticketPlanRepo.update(ticketPlan._id, ticketPlan);
}
1. 개발자 전용 API (예:dev/ticket-plan/update-courts)
// dev.controller.ts
@Controller('dev/ticket-plan')
export class DevTicketPlanController {
constructor(private readonly ticketPlanService: TicketPlanService) {}
@Post('update-courts')
@UseGuards(AdminOnlyGuard) // 혹은 환경별 접근제한
async updateCourts(@Body() dto: UpdateTicketPlanCourtsDto) {
await this.ticketPlanService.updateTicketPlanCourts(dto.academyName, dto.ticketPlanName, dto.newCourtIds);
return { success: true };
}
}
export class UpdateTicketPlanCourtsDto {
@IsString() academyName: string;
@IsString() ticketPlanName: string;
@IsArray() @IsMongoId({ each: true }) newCourtIds: string[];
}
2. NestJS CLI 명령어 지원 (Command Mode)
NestJS는 @nestjs/cli로 직접 명령어를 추가하긴 어렵지만, nestjs-command나 @commander-js/extra-typings을 사용하는 방식이 있습니다.
// ticket-plan.command.ts
import { Command, CommandRunner, Option } from 'nest-commander';
@Command({ name: 'ticket-plan:update-courts', description: 'Update courts for a ticket plan' })
export class UpdateCourtsCommand extends CommandRunner {
constructor(private readonly ticketPlanService: TicketPlanService) {
super();
}
async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
const [academyName, ticketPlanName, ...courtIds] = passedParams;
await this.ticketPlanService.updateTicketPlanCourts(academyName, ticketPlanName, courtIds);
console.log(`Updated ticket plan courts for ${ticketPlanName}`);
}
}
# 실행 예시
$ nestjs ticket-plan:update-courts "XX 아카데미" "1개월권" 60b... 61c... 62f...
🔐 보안 팁
-
API 방식: process.env.NODE_ENV !== 'production'인 경우에만 API Enable
-
CLI 방식: production에서도 제한된 권한 계정에서 안전하게 실행 가능
📌 확장 고려사항
- ID가 아닌 이름 기반으로 조작 가능해야 사용 편리 (ObjectId 추측 불필요)
- 동일한 구조로 다양한 DevOps 기능 추가 가능
- 예: "아카데미의 휴일을 설정해주세요" → AcademyHolidayService.setHolidayByName('XX 아카데미', ['2025-06-03'])
- "특정 유저의 예약 목록을 삭제해주세요" 등
✅ 결론
NestJS 프로젝트에선 서비스 계층을 기준으로 명령형 로직을 묶고, 그 위에 @Controller와 @Command를 모두 붙여주는 방식이 가장 유연합니다.
클린하고 재사용 가능한 로직 구조를 유지하면서도, 빠른 테스트와 조작이 가능합니다.